package com.my.spring.design;

import java.beans.Introspector;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Zijian Liao
 * @since 1.0.0
 */
public class ConfigurationClassProcessor {

    private final BeanFactory beanFactory;

    public ConfigurationClassProcessor(BeanFactory beanFactory){
        this.beanFactory = beanFactory;
    }

    public void scan( Class<?> configClass) {
        // 解析配置类，获取到扫描包路径
        String basePackages = this.getBasePackages(configClass);
        // 使用扫描包路径进行文件遍历操作
        this.doScan(basePackages);
        // 遍历beanPostProcessor接口
        List<String> beanNames = beanFactory.getBeanNamesByType(BeanPostProcessor.class);
        if(!beanNames.isEmpty()){
            for (String beanName : beanNames) {
                BeanPostProcessor beanPostProcessor = (BeanPostProcessor) beanFactory.getBean(beanName);
                beanFactory.registerBeanPostProcessor(beanPostProcessor);
            }
        }
    }


    @SuppressWarnings(value = "all")
    private void doScan(String basePackages) {
        List<BeanDefinition> beanDefinitionList = findComponentBean(basePackages);
        for (BeanDefinition beanDefinition : beanDefinitionList) {
            beanFactory.registerBeanDefinition(beanDefinition.getBeanName(), beanDefinition);
        }
    }

    @SuppressWarnings(value = "all")
    private List<BeanDefinition> findComponentBean(String basePackages){
        List<BeanDefinition> beanDefinitionList = new ArrayList<>();
        // 获取资源信息
        URI resource = this.getResource(basePackages);

        File dir = new File(resource.getPath());
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                // 递归扫描
                doScan(basePackages + "." + file.getName());
            }
            else {
                // com.my.spring.example + . + Boy.class -> com.my.spring.example.Boy
                String className = basePackages + "." + file.getName().replace(".class", "");
                // 将class存放到classMap中
                BeanDefinition beanDefinition = buildBeanDefinition(className);
                if(beanDefinition != null){
                    beanDefinitionList.add(beanDefinition);
                }
            }
        }
        return beanDefinitionList;
    }

    private BeanDefinition buildBeanDefinition(String className){
        try {
            // 加载类信息
            Class<?> clazz = beanFactory.getClassLoader().loadClass(className);
            // 判断是否标识Component注解
            Component component = clazz.getAnnotation(Component.class);
            if(component != null){
                String beanName = component.value();
                if("".equals(beanName)){
                    // 生成beanName com.my.spring.example.Boy -> boy
                    beanName = this.generateBeanName(clazz);
                }
                // car: com.my.spring.example.Car
                return new BeanDefinition(clazz, beanName);
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    private URI getResource(String basePackages){
        // 将包格式替换为文件路径格式
        String packageSearchPath = basePackages.replace(".", "/");
        try {
            // 根据路径获取资源
            return beanFactory.getClassLoader().getResource(packageSearchPath).toURI();
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }


    private String generateBeanName(Class<?> clazz){
        return Introspector.decapitalize(clazz.getSimpleName());
    }


    private String getBasePackages(Class<?> configClass) {
        // 从ComponentScan注解中获取扫描包路径
        ComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);
        return componentScan.basePackages();
    }
}
